home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / fileName.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  23KB  |  973 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/StringDefs.h>
  16. #include <X11/Intrinsic.h>
  17. #include <X11/Shell.h>
  18. #include <X11/Xaw/Dialog.h>
  19. #include <X11/Xaw/Command.h>
  20. #include <X11/Xaw/Toggle.h>
  21. #include <X11/Xaw/Form.h>
  22. #include <X11/Xaw/Label.h>
  23. #include <X11/Xaw/List.h>
  24. #include <X11/Xaw/AsciiText.h>
  25. #include <X11/Xaw/Text.h>
  26. #include <X11/Xaw/Viewport.h>
  27. #include <X11/Xaw/Scrollbar.h>
  28.  
  29. #include "Paint.h"
  30. #include "misc.h"
  31. #include "image.h"
  32. #include <stdio.h>
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #if defined(SYSV) || defined(SVR4)
  36. #include <dirent.h>
  37. #else
  38. #include <sys/dir.h>
  39. #endif
  40. #include <pwd.h>
  41.  
  42. #include "rw/rwTable.h"
  43.  
  44. #define MAX_PATH    1024
  45.  
  46. #ifndef NOSTDHDRS
  47. #include <stdlib.h>
  48. #include <unistd.h>
  49. #endif
  50.  
  51. typedef    void    (*voidFunc)();
  52.  
  53. /*
  54. **  swiped from X11/Xfuncproto.h
  55. **   since qsort() may or may not be defined with a constant sub-function
  56. */
  57. #ifndef _Xconst
  58. #if __STDC__ || defined(__cplusplus) || defined(c_plusplus) || (FUNCPROTO&4)
  59. #define _Xconst const
  60. #else
  61. #define _Xconst
  62. #endif
  63. #endif /* _Xconst */
  64.  
  65. static void    *getArgType(Widget);
  66.  
  67. static    void    *lastId = NULL;
  68.  
  69. void    *GetFileNameGetLastId()
  70. {
  71.     if (lastId == NULL)
  72.         return RWtableGetReaderID();
  73.     return lastId;
  74. }
  75.  
  76. /*
  77. **  "Std" Save functions
  78. */
  79.  
  80. static void    stdSaveCommonCallback(Widget paint, char *file, Boolean flag, RWwriteFunc f)
  81. {
  82.     Pixmap        pix, mask = None;
  83.         int            width, height;
  84.     Colormap    cmap;
  85.     Image        *image;
  86.  
  87.     if (*file == '\0') {
  88.         Notice(paint,"No file name supplied");
  89.         return;
  90.     }
  91.  
  92.     if (flag) {
  93.         PwGetPixmap(paint, &pix, &width, &height);
  94.     } else {
  95.         if (!PwRegionGet(paint, &pix, &mask)) {
  96.             Notice(paint,"Unable to get region");
  97.             return;
  98.         }
  99.     }
  100.     XtVaGetValues(paint, XtNcolormap, &cmap, NULL);
  101.  
  102.     if ((image = PixmapToImage(paint, pix, cmap)) == NULL) {
  103.         Notice(paint,"Unable to create image for saving");
  104.         return;
  105.     }
  106.     if (mask != None) 
  107.         PixmapToImageMask(paint, image, mask);
  108.  
  109.     image->refCount++;
  110.     if (f(file, image)) {
  111.         Notice(paint,"Error saving file:\n   %s", RWGetMsg());
  112.     } else if (flag)
  113.         XtVaSetValues(paint, XtNdirty, False, NULL);
  114.  
  115.     image->refCount--;
  116.     ImageDelete(image);
  117. }
  118. static void saveRegionFileCalback(Widget paint, XtPointer str, XtPointer func)
  119. {
  120.     stdSaveCommonCallback(paint, (char *)str, False, (RWwriteFunc)func);
  121. }
  122. static void saveFileCalback(Widget paint, XtPointer str, XtPointer func)
  123. {
  124.     char    *cp;
  125.  
  126.     stdSaveCommonCallback(paint, (char *)str, True, (RWwriteFunc)func);
  127.  
  128.     if ((cp = strrchr(str, '/')) == NULL)
  129.         cp = str;
  130.     else 
  131.         cp++;
  132.  
  133.     XtVaSetValues(GetShell(paint), XtNtitle, str, XtNiconName, cp, NULL);
  134. }
  135.  
  136. void StdSaveRegionFile(Widget w, XtPointer paintArg, XtPointer junk)
  137. {
  138.     Widget    paint = (Widget)paintArg;
  139.  
  140.         if (PwRegionGet(paint, NULL, NULL))
  141.         GetFileName(paint, True, NULL, saveRegionFileCalback, NULL);
  142.     else
  143.         Notice(paint, "No region selected presently");
  144. }
  145.  
  146. void StdSaveAsFile(Widget w, XtPointer paintArg, XtPointer junk)
  147. {
  148.     Widget    paint = (Widget)paintArg;
  149.     String    name;
  150.     String    nm = XtName(GetShell(paint));
  151.  
  152.     XtVaGetValues(GetShell(paint), XtNtitle, &name, NULL);
  153.  
  154.     if (strcmp(name, "Untitled") == 0 || strcmp(nm, name) == 0)
  155.         name = NULL;
  156.  
  157.     GetFileName(paint, True, name, saveFileCalback, NULL);
  158. }
  159. void StdSaveFile(Widget w, XtPointer paintArg, XtPointer junk)
  160. {
  161.     Widget        paint = (Widget)paintArg;
  162.     String        name = NULL;
  163.     String        nm = XtName(GetShell(paint));
  164.     voidFunc    f = NULL;
  165.     void        *id;
  166.  
  167.     if (strcmp(nm, "Canvas") == 0) {
  168.         XtVaGetValues(GetShell(paint), XtNtitle, &name, NULL);
  169.  
  170.         if (strcmp(name, "Untitled") == 0 || strcmp(nm, name) == 0)
  171.             name = NULL;
  172.     }
  173.  
  174.     if (name != NULL) {
  175.         if ((id = getArgType(paint)) != NULL) {
  176.             f = (voidFunc)RWtableGetWriter(id);
  177.         } else if ((id = GraphicGetReaderId(paint)) != NULL) {
  178.             f = (voidFunc)RWtableGetWriter(RWtableGetEntry(id));
  179.         }
  180.  
  181.         if (f != NULL) {
  182.             stdSaveCommonCallback(paint, name, True, (RWwriteFunc)f);
  183.             return;
  184.  
  185.         }
  186.     }
  187.     GetFileName(paint, True, name, saveFileCalback, NULL);
  188. }
  189.  
  190. /*
  191. **
  192. */
  193. void *ReadMagic(char *file)
  194. {
  195.     RWreadFunc    f = RWtableGetReader(RWtableGetEntry(MAGIC_READER));
  196.  
  197.     return (void *)f(file);
  198. }
  199.  
  200. /*
  201. **  The code begins
  202. */
  203. typedef struct arg_s {
  204.     XtCallbackProc    okFunc;
  205.     void        *type;
  206.     Boolean        isRead, isSimple;
  207.     Widget        w, text, scrollbar;
  208.     XtPointer    closure;
  209.     char        dirname[MAX_PATH];
  210.     Widget        list, cwd_w, info;
  211.     int        first;
  212.     Boolean        isPoped;
  213.     /*
  214.     **  Use for caching, list purposes
  215.     */
  216.     Widget        parent;
  217.     int        browserType;
  218.     struct arg_s    *next;
  219. } arg_t;
  220.  
  221. static void fileTypeCallback(Widget w, XtPointer argArg, XtPointer junk)
  222. {
  223.     arg_t    *arg = (arg_t*)argArg;
  224.     String    nm = XtName(w);
  225.  
  226.     arg->type = RWtableGetEntry(nm);
  227. }
  228.  
  229. static void emptyList(arg_t *arg)
  230. {
  231.     String    *strs;
  232.     int    i, n;
  233.  
  234.     if (arg->first) {
  235.         arg->first = False;
  236.         return;
  237.     }
  238.  
  239.     XtVaGetValues(arg->list, XtNnumberStrings, &n, 
  240.                  XtNlist, &strs,
  241.                  NULL);
  242.  
  243.     for (i = 0; i < n; i++)
  244.         XtFree((XtPointer)strs[i]);
  245.     XtFree((XtPointer)strs);
  246. }
  247.  
  248. static char *doDirname(arg_t *arg, char *file)
  249. {
  250.     static char    newPath[MAX_PATH];
  251.     char        *cp;
  252.  
  253.     if (file == NULL) {
  254. #ifdef NOSTDHDRS
  255.         getwd(newPath);
  256. #else
  257.         getcwd(newPath, sizeof(newPath));
  258. #endif
  259.         return newPath;
  260.     }
  261.     if (*file == '~') {
  262.         struct passwd    *pw;
  263.  
  264.         file++;
  265.         if (*file == '/' || *file == '\0') {
  266.             pw = getpwuid(getuid());
  267.         } else {
  268.             char    buf[80], *bp = buf;
  269.  
  270.             while (*file != '/' && *file != '\0')
  271.                 *bp++ = *file++;
  272.             *bp = '\0';
  273.             pw = getpwnam(buf);
  274.         }
  275.         if (pw == NULL)
  276.             return NULL;
  277.         while (*file == '/')
  278.             file++;
  279.         strcpy(newPath, pw->pw_dir);
  280.     } else if (*file == '/') {
  281.         file++;
  282.         newPath[0] = '\0';
  283.     } else {
  284.         strcpy(newPath, arg->dirname);
  285.     }
  286.     if (strcmp(newPath, "/") != 0)
  287.         strcat(newPath, "/");
  288.     while (*file != '\0') {
  289.         char        *ep;
  290.  
  291.         if ((ep = strchr(file, '/')) == NULL)
  292.             ep = file + strlen(file);
  293.         if (strncmp(file, "./", 2) == 0 || strcmp(file, ".") == 0)
  294.             goto bottom;
  295.         if (strncmp(file, "../", 3) == 0 || strcmp(file, "..") == 0) {
  296.             /*
  297.             **  First strip trailing '/'
  298.             */
  299.             char    *cp = newPath + strlen(newPath) - 1;
  300.             if (cp != newPath)
  301.                 *cp = '\0';
  302.             cp = strrchr(newPath, '/');
  303.             if (cp == newPath)
  304.                 strcpy(newPath, "/");
  305.             else
  306.                 *cp = '\0';
  307.             goto bottom;
  308.         }
  309.         strncat(newPath, file, ep - file);
  310. bottom:
  311.         file = ep;
  312.         if (*file == '/')
  313.             strcat(newPath, "/");
  314.         while (*file == '/')
  315.             file++;
  316.     }
  317.  
  318.     /*
  319.     **  Strip any trailing '/'s
  320.     */
  321.     cp = newPath + strlen(newPath) - 1;
  322.     if (*cp == '/' && cp != newPath)
  323.         *cp = '\0';
  324.         
  325.     return newPath;
  326. }
  327.  
  328. static int strqsortcmp(char **a, char **b)
  329. {
  330.     String    astr = *a;
  331.     String    bstr = *b;
  332.     String    aend = astr + strlen(astr) - 1;
  333.     String    bend = bstr + strlen(bstr) - 1;
  334.  
  335.     if (strncmp(astr, "../", 3) == 0)
  336.         return -1;
  337.     if (strncmp(bstr, "../", 3) == 0)
  338.         return  1;
  339.  
  340.     if (*aend == '/' && *bend != '/')
  341.         return -1;
  342.     if (*aend != '/' && *bend == '/')
  343.         return  1;
  344.     return strcmp(astr, bstr);
  345. }
  346.  
  347. static void setCWD(arg_t *arg, char *dir) 
  348. {
  349.     DIR        *dirp;
  350. #if defined(SYSV) || defined(SVR4)
  351.     struct dirent    *e;
  352. #else
  353.     struct direct    *e;
  354. #endif
  355.     int        count = 0, i = 0;
  356.     int        dirCount = 0, fileCount = 0;
  357.     String        *list;
  358.     char        fileStr[MAX_PATH], *filePtr;
  359.     static char    infoStr[256];
  360.     struct stat    statbuf;
  361.     Widget        sb;
  362.  
  363.     if (dir == NULL)
  364.         dir = arg->dirname;
  365.  
  366.     if (stat(dir, &statbuf) < 0 || (statbuf.st_mode & S_IFDIR) == 0)
  367.         return;
  368.  
  369.     if ((dirp = opendir(dir)) == NULL)
  370.         return;
  371.  
  372.     StateSetBusyWatch(True);
  373.  
  374.     while (readdir(dirp) != NULL)
  375.         count++;
  376.     rewinddir(dirp);
  377.  
  378.     list = (String *)XtCalloc(sizeof(String *), count + 1);
  379.  
  380.     strcpy(fileStr, dir == NULL ? arg->dirname : dir);
  381.     filePtr = fileStr + strlen(fileStr);
  382.     *filePtr++ = '/';
  383.     while ((e = readdir(dirp)) != NULL) {
  384.         struct stat    statbuf;
  385.         char        *nm = e->d_name;
  386.         
  387.         if (nm[0] == '.') {
  388.             /*
  389.             **  Skip '.'
  390.             */
  391.             if (nm[1] == '\0')
  392.                 continue;
  393.             if (nm[1] == '.' && nm[2] == '\0') {
  394.                 list[i++] = XtNewString("../ (Go up 1 directory level)");
  395.                 continue;
  396.             }
  397.         }
  398.         strcpy(filePtr, nm);
  399.         if (stat(fileStr, &statbuf) < 0) {
  400.             list[i++] = XtNewString(nm);
  401.             continue;
  402.         }
  403.         if ((statbuf.st_mode & S_IFDIR) != 0) {
  404.             list[i] = XtMalloc(sizeof(char) * strlen(nm) + 2);
  405.             strcpy(list[i], nm);
  406.             strcat(list[i], "/");
  407.             i++;
  408.             dirCount++;
  409.             continue;
  410.         }
  411.         /*
  412.         **  Now only if it is a file.
  413.         */
  414.         if ((statbuf.st_mode & (S_IFMT & ~S_IFLNK)) == 0) {
  415.             list[i++] = XtNewString(nm);
  416.             fileCount++;
  417.         }
  418.     }
  419.  
  420.     closedir(dirp);
  421.  
  422.     emptyList(arg);
  423.  
  424.     qsort(list, i, sizeof(String), (int (*)(_Xconst void *,_Xconst void *))strqsortcmp);
  425.  
  426.     if (dir != NULL) {
  427.         strcpy(arg->dirname, dir);
  428.         XtVaSetValues(arg->cwd_w, XtNlabel, dir, NULL);
  429.     }
  430.  
  431.     XawListChange(arg->list, list, i, 0, True);
  432.     XtVaSetValues(arg->text, XtNstring, "", NULL);
  433.     sprintf(infoStr, "%d Directories, %d Files", dirCount, fileCount);
  434.     XtVaSetValues(arg->info, XtNlabel, infoStr, NULL);
  435.  
  436.     if ((sb = XtNameToWidget(arg->scrollbar, "vertical")) != None) {
  437.         float    top = 0.0;
  438.  
  439.         XawScrollbarSetThumb(sb, top, -1.0);
  440.         XtCallCallbacks(sb, XtNjumpProc, (XtPointer)&top);
  441.     }
  442.  
  443.     StateSetBusyWatch(False);
  444. }
  445.  
  446. static void okCallback(Widget w, XtPointer argArg, XtPointer junk)
  447. {
  448.     arg_t        *arg = (arg_t *)argArg;
  449.     String        str;
  450.     voidFunc    f;
  451.     struct stat    statbuf;
  452.     char         *file;
  453.     char        *cp;
  454.     char        *nm;
  455.     
  456.     XtVaGetValues(arg->text, XtNstring, &str, NULL);
  457.     if (str == NULL || *str == '\0') {
  458.         XawListReturnStruct    *lr = XawListShowCurrent(arg->list);
  459.  
  460.         if (lr->list_index == XAW_LIST_NONE)
  461.             return;
  462.         str = lr->string;
  463.     }
  464.  
  465.     /*
  466.     **  Got a valid string, check to see if it is a directory
  467.     **    if not try and read/write the file.
  468.     */
  469.     if ((file = doDirname(arg, str)) == NULL) {
  470.         Notice(w, "No such file or directory:\n     %s",str);
  471.         return;
  472.     }
  473.     if (stat(file, &statbuf) >= 0 && (statbuf.st_mode & S_IFDIR) != 0) {
  474.         setCWD(arg, file);
  475.         return;
  476.     }
  477.     if ((cp = strrchr(file, '/')) != NULL) {
  478.         *cp = '\0';
  479.         if (stat(file, &statbuf) >= 0 && (statbuf.st_mode & S_IFDIR) != 0)
  480.             setCWD(arg, file);
  481.         *cp = '/';
  482.     }
  483.  
  484.     arg->isPoped = False;
  485.     XtPopdown(GetShell(w));
  486.  
  487.     if (arg->isSimple) {
  488.         arg->okFunc(arg->w, (XtPointer)arg->closure, (XtPointer)file);
  489.         return;
  490.     }
  491.  
  492.     if (arg->isRead) 
  493.         f = (voidFunc)RWtableGetReader(arg->type);
  494.     else
  495.         f = (voidFunc)RWtableGetWriter(arg->type);
  496.  
  497.     if (arg->type != NULL && strcmp(nm = RWtableGetId(arg->type), MAGIC_READER) != 0)
  498.         lastId = (void*)nm;
  499.     else
  500.         lastId = NULL;
  501.  
  502.     StateSetBusy(True);
  503.     if (arg->okFunc != NULL) {
  504.         if (!arg->isRead) {
  505.             arg->okFunc(arg->w, file, (XtPointer)f);
  506.         } else {
  507.             Image    *image = ((RWreadFunc)f)(file);
  508.             if (image == NULL)
  509.                 Notice(w, "Unable to open input file \"%s\"\n   %s", file, RWGetMsg());
  510.             else
  511.                 arg->okFunc(arg->w, (XtPointer)file, (XtPointer)image);
  512.         }
  513.     }
  514.     StateSetBusy(False);
  515. }
  516.  
  517. static void cancelCallback(Widget w, XtPointer argArg, XtPointer junk)
  518. {
  519.     arg_t            *arg = (arg_t *)argArg;
  520.     arg->isPoped = False;
  521.     XtPopdown(GetShell(w));
  522. }
  523.  
  524. static void listCallback(Widget bar, XtPointer argArg, XtPointer itemArg)
  525. {
  526.     XawListReturnStruct    *item = (XawListReturnStruct *)itemArg;
  527.     arg_t            *arg = (arg_t *)argArg;
  528.     String            str, label;
  529.  
  530.     if (strncmp(item->string, "../", 3) == 0)
  531.         label = "../";
  532.     else
  533.         label = item->string;
  534.  
  535.     XtVaGetValues(arg->text, XtNstring, &str, NULL);
  536.  
  537.     if (strcmp(str, label) == 0)
  538.         okCallback(bar, argArg, NULL);
  539.     else
  540.         XtVaSetValues(arg->text, XtNstring, label, NULL);
  541. }
  542.  
  543. static Widget    buildBrowser(Widget parent, char *title, arg_t *arg)
  544. {
  545.     static Boolean        inited = False;
  546.     static XtTranslations    trans, toglt;
  547.     Widget            form;
  548.     Widget            title_w, name, list, vport, cwd, info;
  549.  
  550.     if (!inited) {
  551.         inited = True;
  552.  
  553.         trans = XtParseTranslationTable("#override\n\
  554.                          <Key>Return: no-op()\n\
  555.                          <Key>Linefeed: no-op()\n\
  556.                          Ctrl<Key>M: no-op()\n\
  557.                          Ctrl<Key>J: no-op()\n");
  558.         toglt = XtParseTranslationTable("<BtnDown>,<BtnUp>: set() notify()");
  559.     }
  560.  
  561. #ifdef NOSTDHDRS
  562.     getwd(arg->dirname);
  563. #else
  564.     getcwd(arg->dirname, sizeof(arg->dirname));
  565. #endif
  566.  
  567.     form = XtVaCreateManagedWidget("broswer", 
  568.                     formWidgetClass, parent,
  569.                     XtNborderWidth, 0,
  570.                     XtNright, XtChainRight,
  571.                     XtNleft, XtChainLeft,
  572.                     XtNtop, XtChainTop,
  573.                     NULL);
  574.     
  575.     title_w = XtVaCreateManagedWidget("title", 
  576.                     labelWidgetClass, form,
  577.                     XtNborderWidth, 0,
  578.                     XtNlabel, title,
  579.                     XtNtop, XtChainTop,
  580.                     XtNbottom, XtChainTop,
  581.                     XtNjustify, XtJustifyLeft,
  582.                     NULL);
  583.  
  584.     name  = XtVaCreateManagedWidget("name",
  585.                     asciiTextWidgetClass, form,
  586.                     XtNfromVert, title_w,
  587.                     XtNeditType, XawtextEdit,
  588.                     XtNwrap, XawtextWrapNever,
  589.                     XtNresize, XawtextResizeWidth,
  590.                     XtNtranslations, trans,
  591.                     XtNbottom, XtChainTop,
  592.                     XtNtop, XtChainTop,
  593.                     XtNwidth, 250,
  594.                     NULL);
  595.  
  596.     vport = XtVaCreateManagedWidget("vport", 
  597.                     viewportWidgetClass, form,
  598.                     XtNfromVert, name,
  599.                     XtNtop, XtChainTop,
  600.                     XtNbottom, XtChainBottom,
  601.                     XtNallowVert, True,
  602.                     XtNallowHoriz, True,
  603.                     XtNuseBottom, True,
  604.                     XtNuseRight, True,
  605.                     XtNwidth, 250,
  606.                     XtNheight, 200,
  607.                     NULL);
  608.  
  609.     list  = XtVaCreateManagedWidget("files",
  610.                     listWidgetClass, vport,
  611.                     XtNborderWidth, 1,
  612.                     XtNverticalList, True,
  613.                     XtNforceColumns, True,
  614.                     XtNdefaultColumns, 1,
  615.                     XtNnumberStrings, 0,
  616.                     NULL);
  617.  
  618.     cwd   = XtVaCreateManagedWidget("cwd", 
  619.                     labelWidgetClass, form,
  620.                     XtNlabel, arg->dirname,
  621.                     XtNborderWidth, 0,
  622.                     XtNfromVert, vport,
  623.                     XtNtop, XtChainBottom,
  624.                     XtNbottom, XtChainBottom,
  625.                     XtNjustify, XtJustifyLeft,
  626.                     XtNresizable, True,
  627.                     NULL);
  628.     info  = XtVaCreateManagedWidget("info", 
  629.                     labelWidgetClass, form,
  630.                     XtNborderWidth, 0,
  631.                     XtNfromVert, cwd,
  632.                     XtNtop, XtChainBottom,
  633.                     XtNbottom, XtChainBottom,
  634.                     XtNjustify, XtJustifyLeft,
  635.                     NULL);
  636.  
  637.     XtAddCallback(list, XtNcallback, listCallback, (XtPointer)arg);
  638.  
  639.     arg->info  = info;
  640.     arg->cwd_w = cwd;
  641.     arg->list  = list;
  642.     arg->text  = name;
  643.     arg->scrollbar = vport;
  644.  
  645.     arg->first = True;
  646.  
  647.     setCWD(arg, doDirname(arg, NULL));
  648.  
  649.     return form;
  650. }
  651.  
  652. static Widget buildOpenBroswer(Widget w, arg_t *arg)
  653. {
  654.     Widget        shell, browser, okButton, cancelButton, form;
  655.     Widget        toggle, firstToggle = None;
  656.     XtAccelerators    accel;
  657.     XtTranslations    toglt;
  658.     int        i;
  659.     char        **list;
  660.  
  661.     shell = XtVaCreatePopupShell("filebrowser", 
  662.                 transientShellWidgetClass, GetToplevel(w),
  663.                 NULL);
  664.     form = XtVaCreateManagedWidget("form", 
  665.                     formWidgetClass, shell,
  666.                     XtNborderWidth, 0,
  667.                     NULL);
  668.     browser = buildBrowser(form, "Open File Named:", arg);
  669.  
  670.     accel = XtParseAcceleratorTable("#override\n\
  671.                      <Key>Return: set() notify() unset()\n\
  672.                      <Key>Linefeed: set() notify() unset()");
  673.  
  674.     okButton = XtVaCreateManagedWidget("ok",
  675.                 commandWidgetClass, form,
  676.                 XtNfromHoriz, browser,
  677.                 XtNaccelerators, accel,
  678.                 XtNbottom, XtChainTop,
  679.                 XtNleft, XtChainRight,
  680.                 XtNright, XtChainRight,
  681.                 NULL);
  682.     cancelButton = XtVaCreateManagedWidget("cancel",
  683.                 commandWidgetClass, form,
  684.                 XtNfromHoriz, okButton,
  685.                 XtNbottom, XtChainTop,
  686.                 XtNleft, XtChainRight,
  687.                 XtNright, XtChainRight,
  688.                 NULL);
  689.  
  690.     toggle = okButton;
  691.     toglt = XtParseTranslationTable("<BtnDown>,<BtnUp>: set() notify()");
  692.  
  693.     list = RWtableGetReaderList();
  694.  
  695.     for (i = 0; list[i] != NULL; i++) {
  696.         toggle = XtVaCreateManagedWidget(list[i],
  697.                     toggleWidgetClass, form,
  698.                     XtNtranslations, toglt,
  699.                     XtNradioGroup, firstToggle,
  700.                     XtNfromVert, toggle,
  701.                     XtNfromHoriz, browser,
  702.                     XtNtop, XtChainBottom,
  703.                     XtNbottom, XtChainBottom,
  704.                     XtNleft, XtChainRight,
  705.                     XtNright, XtChainRight,
  706.                     NULL);
  707.         if (firstToggle == None) {
  708.             arg->type = NULL;
  709.             XtVaSetValues(toggle, XtNstate, True,
  710.                           XtNvertDistance, 100, 
  711.                           NULL);
  712.             firstToggle = toggle;
  713.         }
  714.         XtAddCallback(toggle, XtNcallback, fileTypeCallback, (XtPointer)arg);
  715.     }
  716.  
  717.     arg->isSimple = False;
  718.     arg->isRead = True;
  719.  
  720.     XtAddCallback(okButton, XtNcallback, okCallback, (XtPointer)arg);
  721.     XtAddCallback(cancelButton, XtNcallback, cancelCallback, (XtPointer)arg);
  722.     AddDestroyCallback(shell, (void (*)(Widget, void *, XEvent *))cancelCallback, (XtPointer)arg);
  723.  
  724.     XtSetKeyboardFocus(form, arg->text);
  725.     XtInstallAccelerators(arg->text, okButton);
  726.  
  727.     return shell;
  728. }
  729.  
  730. static Widget buildSaveBroswer(Widget w, arg_t *arg)
  731. {
  732.     Widget        shell, browser, okButton, cancelButton, form;
  733.     Widget        toggle, firstToggle = None;
  734.     XtAccelerators    accel;
  735.     XtTranslations    toglt;
  736.     int        i;
  737.     char        **list, *rdr = NULL;
  738.  
  739.     shell = XtVaCreatePopupShell("filebrowser", 
  740.                 transientShellWidgetClass, GetToplevel(w),
  741.                 NULL);
  742.     form = XtVaCreateManagedWidget("form", 
  743.                     formWidgetClass, shell,
  744.                     XtNborderWidth, 0,
  745.                     NULL);
  746.     browser = buildBrowser(form, "Save In File:", arg);
  747.  
  748.     accel = XtParseAcceleratorTable("#override\n\
  749.                      <Key>Return: set() notify() unset()\n\
  750.                      <Key>Linefeed: set() notify() unset()");
  751.  
  752.     okButton = XtVaCreateManagedWidget("ok",
  753.                 commandWidgetClass, form,
  754.                 XtNfromHoriz, browser,
  755.                 XtNaccelerators, accel,
  756.                 XtNbottom, XtChainTop,
  757.                 NULL);
  758.     cancelButton = XtVaCreateManagedWidget("cancel",
  759.                 commandWidgetClass, form,
  760.                 XtNfromHoriz, okButton,
  761.                 XtNbottom, XtChainTop,
  762.                 NULL);
  763.  
  764.     toggle = okButton;
  765.     toglt = XtParseTranslationTable("<BtnDown>,<BtnUp>: set() notify()");
  766.     list = RWtableGetWriterList();
  767.  
  768.     if (RWtableGetWriter(GraphicGetReaderId(w)) != NULL) {
  769.         rdr = (char*)GraphicGetReaderId(w);
  770.     }
  771.     for (i = 0; list[i] != NULL; i++) {
  772.         toggle = XtVaCreateManagedWidget(list[i],
  773.                     toggleWidgetClass, form,
  774.                     XtNtranslations, toglt,
  775.                     XtNradioGroup, firstToggle,
  776.                     XtNfromVert, toggle,
  777.                     XtNfromHoriz, browser,
  778.                     XtNtop, XtChainBottom,
  779.                     XtNbottom, XtChainBottom,
  780.                     NULL);
  781.         if (firstToggle == None) {
  782.             arg->type = NULL;
  783.             XtVaSetValues(toggle, XtNvertDistance, 100, NULL);
  784.             firstToggle = toggle;
  785.             if (rdr == NULL)
  786.                 XtVaSetValues(toggle, XtNstate, True, NULL);
  787.         }
  788.         if (rdr != NULL && strcmp(rdr, list[i]) == 0) {
  789.             arg->type = RWtableGetEntry(list[i]);
  790.             XtVaSetValues(toggle, XtNstate, True, NULL);
  791.         }
  792.         XtAddCallback(toggle, XtNcallback, fileTypeCallback, (XtPointer)arg);
  793.     }
  794.  
  795.     arg->isSimple = False;
  796.     arg->isRead = False;
  797.  
  798.     XtAddCallback(okButton, XtNcallback, okCallback, (XtPointer)arg);
  799.     XtAddCallback(cancelButton, XtNcallback, cancelCallback, (XtPointer)arg);
  800.     AddDestroyCallback(shell, (void (*)(Widget, void *, XEvent *))cancelCallback, (XtPointer)arg);
  801.  
  802.     XtSetKeyboardFocus(form, arg->text);
  803.     XtInstallAccelerators(arg->text, okButton);
  804.  
  805.     return shell;
  806. }
  807.  
  808. static Widget buildSimpleBroswer(Widget w, arg_t *arg, Boolean isSave)
  809. {
  810.     Widget        shell, browser, okButton, cancelButton, form;
  811.     XtAccelerators    accel;
  812.  
  813.     shell = XtVaCreatePopupShell("filebrowser", 
  814.                 transientShellWidgetClass, GetToplevel(w),
  815.                 NULL);
  816.     form = XtVaCreateManagedWidget("form", 
  817.                     formWidgetClass, shell,
  818.                     XtNborderWidth, 0,
  819.                     NULL);
  820.     browser = buildBrowser(form, isSave ? "Save In File:"
  821.                             : "Load from File:"
  822.                         , arg);
  823.  
  824.     accel = XtParseAcceleratorTable("#override\n\
  825.                      <Key>Return: set() notify() unset()\n\
  826.                      <Key>Linefeed: set() notify() unset()");
  827.  
  828.     okButton = XtVaCreateManagedWidget("ok",
  829.                 commandWidgetClass, form,
  830.                 XtNfromHoriz, browser,
  831.                 XtNaccelerators, accel,
  832.                 XtNbottom, XtChainTop,
  833.                 NULL);
  834.     cancelButton = XtVaCreateManagedWidget("cancel",
  835.                 commandWidgetClass, form,
  836.                 XtNfromHoriz, okButton,
  837.                 XtNbottom, XtChainTop,
  838.                 NULL);
  839.  
  840.     arg->isSimple = True;
  841.  
  842.     XtAddCallback(okButton, XtNcallback, okCallback, (XtPointer)arg);
  843.     XtAddCallback(cancelButton, XtNcallback, cancelCallback, (XtPointer)arg);
  844.     AddDestroyCallback(shell, (void (*)(Widget, void *, XEvent *))cancelCallback, (XtPointer)arg);
  845.  
  846.     XtSetKeyboardFocus(form, arg->text);
  847.     XtInstallAccelerators(arg->text, okButton);
  848.  
  849.     return shell;
  850. }
  851.  
  852. /*
  853. **  
  854. **
  855. */
  856.  
  857. static arg_t    *argList = NULL;
  858.  
  859. static void     freeArg(Widget w, arg_t *arg)
  860. {
  861.     arg_t        *c = argList, **pp = &argList;
  862.  
  863.     while (c != arg && c != NULL) {
  864.         pp = &c->next;
  865.         c  = c->next;
  866.     }
  867.  
  868.     *pp = arg->next;
  869.  
  870.     XtDestroyWidget(GetShell(arg->text));
  871.     XtFree((XtPointer)arg);
  872. }
  873.  
  874. static void    *getArgType(Widget w)
  875. {
  876.     arg_t    *cur;
  877.  
  878.     w = GetShell(w);
  879.  
  880.     for (cur = argList; cur != NULL; cur = cur->next) 
  881.         if (cur->parent == w && 
  882.             (cur->browserType == 0 ||
  883.              cur->browserType == 1))
  884.             break;
  885.  
  886.     if (cur == NULL)
  887.         return NULL;
  888.     return cur->type;
  889. }
  890.  
  891. static arg_t    *getArg(Widget w, Boolean type, Boolean *built)
  892. {
  893.     Widget    shell, p = GetShell(w);
  894.     arg_t    *cur;
  895.  
  896.     *built = False;
  897.  
  898.     for (cur = argList; cur != NULL; cur = cur->next)
  899.         if (p == cur->parent && cur->browserType == type)
  900.             return cur;
  901.  
  902.     cur = XtNew(arg_t);
  903.     cur->parent = p;    
  904.     cur->browserType = type;
  905.  
  906.     switch (type) {
  907.     case 0:
  908.         shell = buildOpenBroswer(w, cur);
  909.         break;
  910.     case 1:
  911.         shell = buildSaveBroswer(w, cur);
  912.         break;
  913.     case 2:
  914.         shell = buildSimpleBroswer(w, cur, True);
  915.         break;
  916.     case 3:
  917.         shell = buildSimpleBroswer(w, cur, False);
  918.         break;
  919.     }
  920.  
  921.     cur->next = argList;
  922.     argList   = cur;
  923.  
  924.     XtAddCallback(p, XtNdestroyCallback, (XtCallbackProc)freeArg, (XtPointer)cur);
  925.  
  926.     *built = True;
  927.  
  928.     return cur;
  929. }
  930.  
  931. void GetFileName(Widget w, int type, char *def, XtCallbackProc okFunc, XtPointer data)
  932. {
  933.     arg_t        *arg;
  934.     Boolean        built;
  935.     Position    x,y;
  936.  
  937.     XtVaGetValues(GetShell(w), XtNx, &x, XtNy, &y, NULL);
  938.  
  939.     arg = getArg(w, type, &built);
  940.     arg->closure = data;
  941.  
  942.     XtVaSetValues(GetShell(arg->text), XtNx, x + 24, XtNy, y + 24, NULL);
  943.  
  944.     if (def != NULL && *def != '\0') {
  945.         char    *cp, dirname[MAX_PATH];
  946.         strcpy(dirname, def);
  947.         cp = strrchr(dirname, '/');
  948.  
  949.         if (cp != NULL && cp != dirname) 
  950.             *cp++ = '\0';
  951.         else if (cp == NULL)
  952.             cp = dirname;
  953.  
  954.         if (built) 
  955.             setCWD(arg, doDirname(arg, dirname));
  956.  
  957.         XtVaSetValues(arg->text, XtNstring, cp, 
  958.                           XtNinsertPosition, strlen(cp),
  959.                           NULL);
  960.     } else if (!built) {
  961.         /*
  962.         **  Rescan directory.
  963.         */
  964.         setCWD(arg, NULL);
  965.     }
  966.  
  967.     arg->okFunc = okFunc;
  968.     arg->w      = w;
  969.  
  970.     arg->isPoped = True;
  971.     XtPopup(GetShell(arg->text), XtGrabNone);
  972. }
  973.